////////////////////////////////////////////////////////////////////////////////
//
//  FLEX USER GROUP HOKURIKU
//  Copyright 2009 Flex User Group Hokuriku
//  All Rights Reserved.
// 
//  NOTICE: Flex User Group Hokuriku permits you to use, 
//  modify, and distribute this file 
//  in accordance with the terms of the license agreement accompanying it.
//
////////////////////////////////////////////////////////////////////////////////
package net.fxug.hokuriku.chocolat.service
{
    import flash.errors.IOError;
    import flash.events.DatagramSocketDataEvent;
    import flash.events.EventDispatcher;
    import flash.net.DatagramSocket;
    import flash.utils.ByteArray;

    import mx.logging.ILogger;

    import net.fxug.hokuriku.chocolat.utils.LoggingUtil;

    /**
     * オーディエンスからのブロードキャストによる探索を受け付ける。スピーカー用。
     *
     * [[使い方]]
     *
     * <pre>
     * // 受信して勝手に返信するだけ
     * var sonarReceiver:SonarReceiver = new SonarReceiver(address);
     * sonarReceiver.recieve();
     * </pre>
     *
     * @author shoito
     */
    public class SonarReceiver extends EventDispatcher
    {
        public static const PORT:int = 33333;

        public static const REPLY_FROM_SPEAKER:String = "REPLY_FROM_SPEAKER"; // スピーカーからの応答

        private static var logger:ILogger = LoggingUtil.getLogger(SonarReceiver);

        private static var datagramSocket:DatagramSocket; // close()してもポートが解放されない問題があるため、staticにして再利用

        private var localAddress:String;

        /**
         * コンストラクタ
         *
         * @param localAddress // IPアドレス
         */
        public function SonarReceiver(localAddress:String)
        {
            logger.info("SonarReceiver::new SonarReceiver Address = {0}", localAddress);
            this.localAddress = localAddress;
        }

        /**
         * 待ちうけ開始
         */
        public function recieve():void
        {
            logger.info("SonarReceiver::recieve 受信開始");

            if (!datagramSocket)
            {
                datagramSocket = new DatagramSocket();
                datagramSocket.bind(PORT, localAddress);

                logger.info("Sonar::SonarReceiver bind port = {0} / address = {1}", datagramSocket.localPort, datagramSocket.localAddress);
            }

            datagramSocket.addEventListener(DatagramSocketDataEvent.DATA, dataReceivedEventHandler);
            datagramSocket.receive();
        }

        /**
         * バインドが成功しているかどうか
         *
         * @return
         */
        public function isBound():Boolean
        {
            return (datagramSocket && datagramSocket.bound);
        }

        /**
         * データを受信
         */
        private function dataReceivedEventHandler(event:DatagramSocketDataEvent):void
        {
            logger.debug("Sonar::dataReceivedEventHandler 受信");

            var message:String = event.data.readUTFBytes(event.data.bytesAvailable);
            if (message == Sonar.SEARCH_SPEAKER)
            {
                logger.info("    Received SEARCH_SERVE from {0}:{1} > {2}", event.srcAddress, event.srcPort, message);

                var replyMessage:ByteArray = new ByteArray();
                replyMessage.writeUTFBytes(REPLY_FROM_SPEAKER);

                // オーディエンスに返答
                datagramSocket.send(replyMessage, 0, 0, event.srcAddress, event.srcPort);
            }
            else
            {
                // TODO エラーハンドリング
                logger.info("    undefined message recieved message = " + message);
            }
        }

        /**
         * 終了処理
         */
        public function close():void
        {
            logger.info("SonarReceiver::close");

            if (datagramSocket)
            {
                if (datagramSocket.hasEventListener(DatagramSocketDataEvent.DATA))
                {
                    datagramSocket.removeEventListener(DatagramSocketDataEvent.DATA, dataReceivedEventHandler);
                }
                try
                {
                    datagramSocket.close();
                }
                catch (e:IOError)
                {
                    logger.error("    datagramSocket.close ERROR");
                }
            }
        }
    }
}